package com.statistics.service;


import com.statistics.config.PressForMoneyService;
import com.statistics.config.YhService;
import com.statistics.entity.PressForMoneyDto;
import com.statistics.entity.StatisticsDto;
import com.statistics.entity.YhDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 统计记录
 * @author hewei
 * @date 2022/4/25 10:17
 * @Description
 */
@Service
@Slf4j
public class StatisticsService {

    @Autowired
    private YhService yhService;

    @Autowired
    private PressForMoneyService pressForMoneyService;

    public Map<String,List<StatisticsDto>> statistics(MultipartFile yhFile, MultipartFile importFile){
        final List<YhDto> yhDtos = yhService.analysisYh(yhFile);
        final List<PressForMoneyDto> pressForMoneyDtos = pressForMoneyService.analysisYh(importFile);

        Map<String,List<StatisticsDto>> listMap = new HashMap<>();
        yhDtos.forEach(yhDto -> {
            log.info("名称：{}",yhDto.getName());
            List<StatisticsDto> statisticsDtos = new ArrayList<>();
            AtomicReference<String> phone = new AtomicReference<>();
            // 获取相同卡号身份证号
            List<PressForMoneyDto> collect = pressForMoneyDtos.stream().filter
                    (pfm -> pfm.getIdCard().equals(yhDto.getIdCard()) && pfm.getCardNumber().equals(yhDto.getAccount())).collect(Collectors.toList());
            AtomicBoolean boo = new AtomicBoolean(true);
            List<StatisticsDto> existence = new ArrayList<>();
            collect.forEach(pressForMoneyDto -> {
                existence.clear();
                //  在根据相同卡号身份证号的数据  遍历银行数据 查询银行相同卡号的 其他账号数据
                final List<YhDto> yhList = yhDtos.stream().filter
                        (yh -> yh.getIdCard().equals(pressForMoneyDto.getIdCard())).collect(Collectors.toList());
                final boolean[] list = {true};
                yhList.forEach(yhs -> {
                    List<StatisticsDto> statisticsDtos1 = listMap.get(yhs.getIdCard() + ":" + yhs.getAccount());
                    if (list[0] && null != statisticsDtos1 && !statisticsDtos1.isEmpty()) {
                        existence.addAll(statisticsDtos1);
                        boo.set(false);
                        list[0] = false;
                    }
                });
                // 公债数据需要一样 直接选一条公用
                yhList.forEach(yhs ->{
                    List<StatisticsDto> existenceNew = new ArrayList<>();
                    if (!existence.isEmpty()) {
                        existence.forEach(statisticsDto -> {
                            StatisticsDto statisticsDto1 = new StatisticsDto();
                            BeanUtils.copyProperties(statisticsDto,statisticsDto1);
                            statisticsDto1.setAccount(yhs.getAccount());
                            existenceNew.add(statisticsDto1);
                        });
                        listMap.put(yhs.getIdCard() + ":" + yhs.getAccount(), existenceNew);
                    }

                });

            });
            // 没有公共数据再去遍历 存储新数据
            if (boo.get()) {
                collect.forEach(pressForMoneyDto -> {
                    phone.set(pressForMoneyDto.getPhone());
                    StatisticsDto dto = new StatisticsDto();
                    dto.setOperator("尚兴合");
                    dto.setName(pressForMoneyDto.getName());
                    dto.setIdCard(pressForMoneyDto.getIdCard());
                    dto.setAccount(pressForMoneyDto.getCardNumber());
                    dto.setOperatorDate(pressForMoneyDto.getResultDate());
                    dto.setResultMode(1);
                    dto.setNoticeObj(Integer.parseInt(pressForMoneyDto.getRelationship()));
                    if (StringUtils.isNotBlank(pressForMoneyDto.getPhone())) {
                        dto.setPhone(pressForMoneyDto.getPhone());
                    }
                    if (StringUtils.isNotBlank(pressForMoneyDto.getResult()) && !"无效电话".equals(pressForMoneyDto.getResult())) {
                        dto.setLiaisonResult(pressForMoneyDto.getResult().substring(0, 1));
                        dto.setRecord(pressForMoneyDto.getResultContent());
                    } else {
                        final int liaisonResult = this.getLiaisonResult();
                        dto.setLiaisonResult(liaisonResult + "");
                        dto.setRecord(this.getRecord(liaisonResult));
                    }
                    dto.setResult(getResult(pressForMoneyDto.getResultStatus()));
                    statisticsDtos.add(dto);
                });
                log.info("匹配数据：{}条", statisticsDtos.size());
                List<StatisticsDto> minus = new ArrayList<>();

                if (statisticsDtos.size() > 36) {
                    statisticsDtos.forEach(statisticsDto -> {
                        if (StringUtils.isBlank(statisticsDto.getLiaisonResult())
                                || statisticsDto.getLiaisonResult().equals("3")
                                || statisticsDto.getLiaisonResult().equals("6")
                                || statisticsDto.getLiaisonResult().equals("5")) {
                            minus.add(statisticsDto);
                        }
                        if (statisticsDtos.size() - minus.size() < 36) {
                            return;
                        }
                    });
                }
                log.info("需要去除：{}条", minus.size());
                statisticsDtos.removeAll(minus);
                if (statisticsDtos.size() < 26 && statisticsDtos.size() != 0) {
                    try {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        List<Date> dates = randomDate(statisticsDtos);
                        dates.forEach(date -> {
                            StatisticsDto dto = new StatisticsDto();
                            dto.setOperator("尚兴合");
                            dto.setName(yhDto.getName());
                            dto.setIdCard(yhDto.getIdCard());
                            dto.setAccount(yhDto.getAccount());
                            dto.setOperatorDate(sdf.format(date));
                            dto.setResultMode(1);
                            dto.setNoticeObj(1);
                            if (StringUtils.isNotBlank(phone.get())) {
                                dto.setPhone(phone.get());
                            }
                            final int liaisonResult = this.getLiaisonResult();
                            dto.setLiaisonResult(liaisonResult + "");
                            dto.setResult(this.getResult() + "");
                            dto.setRecord(this.getRecord(liaisonResult));
                            statisticsDtos.add(dto);
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    try {
                            List<Date> dates = randomDate(statisticsDtos);
                            AtomicInteger i = new AtomicInteger();
                            dates.forEach(date -> {
                                StatisticsDto statisticsDto = statisticsDtos.get(i.get());
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                statisticsDto.setOperatorDate(sdf.format(date));
                                i.getAndIncrement();
                            });
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                Collections.sort(statisticsDtos, new Comparator<StatisticsDto>() {
                    @Override
                    public int compare(StatisticsDto o1, StatisticsDto o2) {
                        if (null != o2.getOperatorDate() && null != o1.getOperatorDate()) {
                            return o1.getOperatorDate().compareTo(o2.getOperatorDate());
                        }
                        return 1;
                    }
                });
                listMap.put(yhDto.getIdCard()+":"+yhDto.getAccount(),statisticsDtos);
            }

        });
        return listMap;
    }

    public int getLiaisonResult(){
        Random random = new Random();
        int liaisonResult;
        do {
            liaisonResult = random.nextInt(8);
        }while (liaisonResult == 0 || liaisonResult ==1);
        return liaisonResult;
    }

    public int getRandomNumber(int number){
        Random random = new Random();
        int liaisonResult;
        do {
            liaisonResult = random.nextInt(8);
        }while (number <= liaisonResult);
        return liaisonResult;
    }

    public int getResult(){
        Random random = new Random();
        int liaisonResult;
        do {
            liaisonResult = random.nextInt(11);
        }while (liaisonResult == 0
                || liaisonResult ==1
                || liaisonResult ==2
                || liaisonResult ==3
                || liaisonResult ==4);
        return liaisonResult;
    }


    public String getRecord(int number){
        switch (number){
            case 2:
                return "通话中";
            case 3:
                return "无人接听";
            case 4:
                return "关机";
            case 5:
                return "拒接";
            case 6:
                return "暂停服务";
            case 7:
                return "无法接通";
            case 8:
                return "完成协催  短信申请";
            default:
                return "正忙";
        }
    }

    /**
     * 生成size数量的随机时间，位于[start,end)范围内 时间倒序排列

     * @return List<Date>
     * @throws Exception
     */
    public static List<Date> randomDate(List<StatisticsDto> statisticsDtos) throws Exception {
        List<Date> dates = new ArrayList<>();
        if (null != statisticsDtos && !statisticsDtos.isEmpty()) {
            int size = 0;
            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            LocalDateTime currentMonth = LocalDateTime.now();
            /**
             * 判断真实数据是否有时间太低的
             *  重新赋予6个月之内的时间在做筛选
             */
            final LocalDateTime localDateTime = currentMonth.minusMonths(7);
            statisticsDtos.forEach(statisticsDto -> {
                if (StringUtils.isBlank(statisticsDto.getOperatorDate())) {
                    try {
                        final List<Date> date = randomDate(fmt.format(localDateTime), fmt.format(currentMonth), 1, 0);
                        statisticsDto.setOperatorDate(sdf.format(date.get(0)));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
               else if(LocalDateTime.parse(statisticsDto.getOperatorDate(), fmt).isBefore(localDateTime)){
                    try {
                        final List<Date> date = randomDate(fmt.format(localDateTime), fmt.format(currentMonth), 1, 0);
                        statisticsDto.setOperatorDate(sdf.format(date.get(0)));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
            /**
             * start 开始时间
             * end 结束时间
             * size 生成时间个数
             * order 结果排序：-1时间倒叙，0 乱序，1时间正序
             */
            for (int i = 0; i < 7; i++) {
                size = getRandomNumber();
                String start = fmt.format(currentMonth.minusMonths(i + 1));
                String end = fmt.format(currentMonth.minusMonths(i));
                AtomicInteger minus = new AtomicInteger();
                statisticsDtos.forEach(statisticsDto -> {
                    final String operatorDate = statisticsDto.getOperatorDate();
                    if (LocalDateTime.parse(operatorDate, fmt).isAfter(LocalDateTime.parse(start, fmt))
                            &&
                            LocalDateTime.parse(operatorDate, fmt).isBefore(LocalDateTime.parse(end, fmt))) {
                        minus.addAndGet(1);
                        log.info("名称：{},已存在数据：{}", statisticsDto.getName(), minus.get());
                    }
                });
                log.info("在：{}和{}时间段之前有：{}条数据", start, end, minus.get());
                if (size - minus.get() <= 0) {
                    continue;
                }
                dates.addAll(randomDate(start, end, size - minus.get(), 0));
            }
            return dates;
        }
        return dates;
    }

    /**
     * 生成size数量的随机时间，位于[start,end)范围内 时间倒序排列
     * @param start 开始时间
     * @param end 结束时间
     * @param size 生成时间个数
     * @param order 结果排序：-1时间倒叙，0 乱序，1时间正序
     * @return List<Date>
     * @throws Exception
     */
    public static List<Date> randomDate(String start, String end, int size, int order) throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date startTime = sdf.parse(start);
        Date endTime = sdf.parse(end);

        Random random = new Random();
        List<Date> dates = random.longs(size, startTime.getTime(), endTime.getTime()).mapToObj(t -> new Date(t)).collect(Collectors.toList());

        dates.sort((t1,t2)->{
            return t1.compareTo(t2) * order;
        });

        return dates;
    }

    public static int getRandomNumber(){
        Random random = new Random();
        int liaisonResult;
        do {
            liaisonResult = random.nextInt(6);
        }while (liaisonResult == 0
                || liaisonResult ==1
                || liaisonResult ==2
                || liaisonResult ==3);
        return liaisonResult;
    }


    public String getResult(String result){
        if (StringUtils.isNotBlank(result)) {
            switch (result) {
                case "FD":
                case "FD1":
                    return "5";
                case "FD2":
                case "MORNING":
                case "FD3":
                    return "6";
                case "PTP":
                case "PTP1":
                case "FULLPTP":
                    return "2";
                case "PTP2":
                    return "4";
                case "AFTERNOON":
                    return "7";
                case "NIGHT":
                case "VISIT":
                    return "8";
                case "CP":
                case "CLOSE":
                    return "1";
                case "SPECIAL":
                    return "11";
                default:
                    return null;
            }
        }else {
            return this.getResult()+"";
        }

    }
}
